#include "devicecontroller.h"
#include <QDebug>
#include <QSerialPortInfo>
#include <QThread>
#include <QJsonObject>
#include <QJsonDocument>

DeviceController::DeviceController(QObject *parent)
    : QObject(parent)
    , m_status(DEVICE_IDLE)
    , m_currentMode(SAMPLING_TIMED)
    , m_statusTimer(nullptr)
    , m_samplingTimer(nullptr)
    , m_serialPort(nullptr)
    , m_auditLogger(nullptr)
{
    // Initialize device parameters with default values
    m_parameters.flow_rate = 0;
    m_parameters.sampling_time = 0;
    m_parameters.sampling_volume = 0;
    m_parameters.battery_level = 100;
    m_parameters.fan_speed = 0;
    m_parameters.temperature = 25.0f;
    m_parameters.humidity = 50.0f;
    
    // Initialize timers
    m_statusTimer = new QTimer(this);
    m_samplingTimer = new QTimer(this);
    
    // Connect timer signals
    connect(m_statusTimer, &QTimer::timeout, this, &DeviceController::updateDeviceStatus);
    connect(m_samplingTimer, &QTimer::timeout, this, &DeviceController::onSamplingTimer);
    
    // Initialize serial port
    m_serialPort = new QSerialPort(this);
    connect(m_serialPort, &QSerialPort::readyRead, this, &DeviceController::onSerialDataReceived);
    
    m_lastError = "";
}

DeviceController::~DeviceController()
{
    shutdownDevice();
}

bool DeviceController::initializeDevice()
{
    qDebug() << "Initializing bacteria sampler device...";
    
    // Connect to device via serial port
    if (!connectToDevice()) {
        m_lastError = "Failed to connect to device";
        logDeviceOperation("INIT", "Device initialization failed - connection error");
        return false;
    }
    
    // Perform device self-test
    if (!performSelfTest()) {
        m_lastError = "Device self-test failed";
        logDeviceOperation("INIT", "Device initialization failed - self-test error");
        return false;
    }
    
    // Start status monitoring
    m_statusTimer->start(1000); // Update every second
    
    m_status = DEVICE_IDLE;
    emit deviceStatusChanged(m_status);
    
    logDeviceOperation("INIT", "Device initialized successfully");
    qDebug() << "Device initialization completed successfully";
    
    return true;
}

void DeviceController::shutdownDevice()
{
    qDebug() << "Shutting down device...";
    
    // Stop any ongoing sampling
    if (m_status == DEVICE_SAMPLING) {
        stopSampling();
    }
    
    // Stop timers
    if (m_statusTimer) {
        m_statusTimer->stop();
    }
    if (m_samplingTimer) {
        m_samplingTimer->stop();
    }
    
    // Stop fan
    stopFan();
    
    // Disconnect from device
    disconnectFromDevice();
    
    m_status = DEVICE_IDLE;
    emit deviceStatusChanged(m_status);
    
    logDeviceOperation("SHUTDOWN", "Device shutdown completed");
}

bool DeviceController::startFan(int speed)
{
    if (speed < 0 || speed > 100) {
        m_lastError = "Invalid fan speed (0-100)";
        return false;
    }
    
    // Send fan start command to device
    QString command = QString("FAN_START:%1").arg(speed);
    if (!sendCommand(command.toLocal8Bit().data())) {
        m_lastError = "Failed to send fan start command";
        return false;
    }
    
    m_parameters.fan_speed = speed * 30; // Convert percentage to RPM (approximate)
    emit fanSpeedChanged(m_parameters.fan_speed);
    
    logDeviceOperation("FAN_START", QString("Fan started at speed %1").arg(speed).toLocal8Bit().data());
    qDebug() << "Fan started at speed:" << speed;
    
    return true;
}

bool DeviceController::stopFan()
{
    // Send fan stop command to device
    if (!sendCommand("FAN_STOP")) {
        m_lastError = "Failed to send fan stop command";
        return false;
    }
    
    m_parameters.fan_speed = 0;
    emit fanSpeedChanged(m_parameters.fan_speed);
    
    logDeviceOperation("FAN_STOP", "Fan stopped");
    qDebug() << "Fan stopped";
    
    return true;
}

bool DeviceController::startSampling(SamplingMode mode, int parameter)
{
    if (m_status == DEVICE_SAMPLING) {
        m_lastError = "Device is already sampling";
        return false;
    }
    
    if (!validateParameters()) {
        m_lastError = "Invalid sampling parameters";
        return false;
    }
    
    m_currentMode = mode;
    m_samplingStartTime = QDateTime::currentDateTime();
    
    // Set sampling parameters based on mode
    if (mode == SAMPLING_TIMED) {
        m_parameters.sampling_time = parameter;
        m_samplingTimer->start(parameter * 1000); // Convert to milliseconds
    } else {
        m_parameters.sampling_volume = parameter;
        // For volume sampling, we'll monitor flow rate and stop when target volume is reached
    }
    
    // Start fan at default speed
    if (!startFan(80)) {
        return false;
    }
    
    m_status = DEVICE_SAMPLING;
    emit deviceStatusChanged(m_status);
    emit samplingStarted(mode);
    
    const char* modeStr = samplingModeToString(mode);
    QString details = QString("Sampling started - Mode: %1, Parameter: %2").arg(modeStr).arg(parameter);
    logDeviceOperation("SAMPLING_START", details.toLocal8Bit().data());
    
    qDebug() << "Sampling started - Mode:" << modeStr << "Parameter:" << parameter;
    
    return true;
}

bool DeviceController::stopSampling()
{
    if (m_status != DEVICE_SAMPLING) {
        m_lastError = "Device is not sampling";
        return false;
    }
    
    m_status = DEVICE_STOPPING;
    emit deviceStatusChanged(m_status);
    
    // Stop sampling timer
    m_samplingTimer->stop();
    
    // Stop fan
    stopFan();
    
    // Calculate sampling results
    QDateTime endTime = QDateTime::currentDateTime();
    int actualTime = m_samplingStartTime.secsTo(endTime);
    int actualVolume = (m_parameters.flow_rate * actualTime) / 60; // L/min * seconds / 60
    
    // Create sampling record
    SamplingRecord record;
    record.start_time = m_samplingStartTime;
    record.end_time = endTime;
    record.actual_time = actualTime;
    record.actual_volume = actualVolume;
    record.mode = m_currentMode;
    record.status = DEVICE_IDLE;
    record.operator_id = "current_user"; // This should be set from user session
    
    // Add to history
    m_samplingHistory.append(record);
    
    m_status = DEVICE_IDLE;
    emit deviceStatusChanged(m_status);
    emit samplingCompleted(record);
    
    logDeviceOperation("SAMPLING_STOP", QString("Sampling completed - Time: %1s, Volume: %2L").arg(actualTime).arg(actualVolume).toLocal8Bit().data());
    qDebug() << "Sampling stopped - Actual time:" << actualTime << "s, Volume:" << actualVolume << "L";
    
    return true;
}

bool DeviceController::setFlowRate(int rate)
{
    if (!validateFlowRate(rate)) {
        m_lastError = "Invalid flow rate";
        return false;
    }
    
    m_parameters.flow_rate = rate;
    emit flowRateChanged(rate);
    
    logDeviceOperation("SET_FLOW_RATE", QString("Flow rate set to %1 L/min").arg(rate).toLocal8Bit().data());
    
    return true;
}

bool DeviceController::setSamplingTime(int seconds)
{
    if (seconds <= 0 || seconds > 86400) { // Max 24 hours
        m_lastError = "Invalid sampling time (1-86400 seconds)";
        return false;
    }
    
    m_parameters.sampling_time = seconds;
    logDeviceOperation("SET_SAMPLING_TIME", QString("Sampling time set to %1 seconds").arg(seconds).toLocal8Bit().data());
    
    return true;
}

bool DeviceController::setSamplingVolume(int volume)
{
    if (!validateSamplingVolume(volume)) {
        m_lastError = "Invalid sampling volume";
        return false;
    }
    
    m_parameters.sampling_volume = volume;
    logDeviceOperation("SET_SAMPLING_VOLUME", QString("Sampling volume set to %1 L").arg(volume).toLocal8Bit().data());
    
    return true;
}

// Getter methods
int DeviceController::getFlowRate() const
{
    return m_parameters.flow_rate;
}

int DeviceController::getBatteryLevel() const
{
    return m_parameters.battery_level;
}

int DeviceController::getFanSpeed() const
{
    return m_parameters.fan_speed;
}

float DeviceController::getTemperature() const
{
    return m_parameters.temperature;
}

float DeviceController::getHumidity() const
{
    return m_parameters.humidity;
}

DeviceStatus DeviceController::getDeviceStatus() const
{
    return m_status;
}

QString DeviceController::getDeviceStatusString() const
{
    return QString(deviceStatusToString(m_status));
}

QList<QVariant> DeviceController::getSamplingHistory() const
{
    QList<QVariant> history;
    for (const auto& record : m_samplingHistory) {
        QVariantMap recordMap;
        recordMap["startTime"] = record.start_time;
        recordMap["endTime"] = record.end_time;
        recordMap["actualTime"] = record.actual_time;
        recordMap["actualVolume"] = record.actual_volume;
        recordMap["mode"] = static_cast<int>(record.mode);
        recordMap["status"] = static_cast<int>(record.status);
        recordMap["operatorId"] = record.operator_id;
        history.append(recordMap);
    }
    return history;
}

bool DeviceController::clearSamplingHistory()
{
    m_samplingHistory.clear();
    logDeviceOperation("CLEAR_HISTORY", "Sampling history cleared");
    return true;
}

bool DeviceController::performSelfTest()
{
    qDebug() << "Performing device self-test...";
    
    // Simulate self-test procedure
    QThread::msleep(1000); // Simulate test time
    
    // Check critical components
    bool fanTest = true;    // Test fan motor
    bool sensorTest = true; // Test flow sensor
    bool batteryTest = m_parameters.battery_level > 10; // Check battery
    
    if (!fanTest || !sensorTest || !batteryTest) {
        m_lastError = "Self-test failed - Hardware error";
        return false;
    }
    
    logDeviceOperation("SELF_TEST", "Device self-test passed");
    qDebug() << "Device self-test completed successfully";
    
    return true;
}

QString DeviceController::getLastError() const
{
    return m_lastError;
}

void DeviceController::setAuditLogger(AuditLogger* logger)
{
    m_auditLogger = logger;
}

// Private slots
void DeviceController::updateDeviceStatus()
{
    // Update battery level (simulate discharge)
    if (m_status == DEVICE_SAMPLING) {
        m_parameters.battery_level = qMax(0, m_parameters.battery_level - 1);
        if (m_parameters.battery_level < 20) {
            emit batteryLow(m_parameters.battery_level);
        }
    }
    
    // Update flow rate (simulate sensor reading)
    if (m_status == DEVICE_SAMPLING) {
        // Simulate flow rate fluctuation
        int baseRate = 28; // Base flow rate
        int variation = (qrand() % 5) - 2; // ±2 L/min variation
        m_parameters.flow_rate = qMax(0, baseRate + variation);
        emit flowRateChanged(m_parameters.flow_rate);
    }
    
    // Update temperature and humidity
    m_parameters.temperature = 25.0f + (qrand() % 10 - 5) * 0.1f; // ±0.5°C variation
    m_parameters.humidity = 50.0f + (qrand() % 20 - 10) * 0.1f;   // ±1% variation
    
    emit temperatureChanged(m_parameters.temperature);
    emit humidityChanged(m_parameters.humidity);
    emit batteryLevelChanged(m_parameters.battery_level);
}

void DeviceController::onSamplingTimer()
{
    // Timed sampling completed
    qDebug() << "Timed sampling completed";
    stopSampling();
}

void DeviceController::onSerialDataReceived()
{
    if (!m_serialPort) return;
    
    QByteArray data = m_serialPort->readAll();
    qDebug() << "Received data from device:" << data;
    
    // Process received data (device responses, sensor readings, etc.)
    // This would be implemented based on the actual device protocol
}

// Private methods
bool DeviceController::sendCommand(const char* command)
{
    if (!isDeviceConnected()) {
        return false;
    }
    
    qDebug() << "Sending command to device:" << command;
    
    // In a real implementation, this would send the command via serial port
    // For simulation, we just log the command
    QByteArray cmdData(command);
    if (m_serialPort && m_serialPort->isOpen()) {
        qint64 bytesWritten = m_serialPort->write(cmdData);
        return bytesWritten == cmdData.size();
    }
    
    // Simulate successful command for testing
    return true;
}

bool DeviceController::readDeviceResponse(char* buffer, int maxSize)
{
    if (!isDeviceConnected() || !buffer || maxSize <= 0) {
        return false;
    }
    
    // In a real implementation, this would read response from serial port
    // For simulation, we return a dummy response
    strncpy(buffer, "OK", maxSize - 1);
    buffer[maxSize - 1] = '\0';
    
    return true;
}

void DeviceController::logDeviceOperation(const char* operation, const char* details)
{
    if (m_auditLogger) {
        AuditLogger::AuditRecord record;
        record.timestamp = QDateTime::currentDateTime();
        record.userId = "system"; // This should be set from user session
        record.action = AuditLogger::System;
        record.tableName = "device_operations";
        record.recordId = QString::number(QDateTime::currentMSecsSinceEpoch());
        record.oldValue = "";
        record.newValue = QString(details);
        record.description = QString("Device Operation: %1 - %2").arg(operation).arg(details);
        
        m_auditLogger->logEvent(record);
    }
    
    qDebug() << "Device Operation:" << operation << "-" << details;
}

void DeviceController::updateBatteryLevel()
{
    // This would read actual battery level from device
    // For simulation, we gradually decrease battery during sampling
    if (m_status == DEVICE_SAMPLING) {
        m_parameters.battery_level = qMax(0, m_parameters.battery_level - 1);
    }
}

void DeviceController::checkFlowRate()
{
    // This would read actual flow rate from device sensors
    // For simulation, we use a base rate with some variation
    if (m_status == DEVICE_SAMPLING) {
        int baseRate = 28;
        int variation = (qrand() % 5) - 2;
        m_parameters.flow_rate = qMax(0, baseRate + variation);
    } else {
        m_parameters.flow_rate = 0;
    }
}

bool DeviceController::validateParameters()
{
    if (m_parameters.battery_level < 10) {
        m_lastError = "Battery level too low for sampling";
        return false;
    }
    
    return true;
}

bool DeviceController::connectToDevice()
{
    // Find available serial ports
    QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
    
    // For simulation, we don't require an actual device
    // In a real implementation, you would:
    // 1. Find the correct port for the bacteria sampler
    // 2. Configure port settings (baud rate, data bits, etc.)
    // 3. Open the connection
    
    qDebug() << "Available serial ports:" << ports.size();
    
    // Simulate successful connection
    return true;
}

void DeviceController::disconnectFromDevice()
{
    if (m_serialPort && m_serialPort->isOpen()) {
        m_serialPort->close();
    }
    
    qDebug() << "Disconnected from device";
}

bool DeviceController::isDeviceConnected() const
{
    // For simulation, always return true
    // In a real implementation, check if serial port is open and responsive
    return true;
}

// C-style helper functions
extern "C" {
    const char* deviceStatusToString(DeviceStatus status)
    {
        switch (status) {
            case DEVICE_IDLE: return "DEVICE_IDLE";
            case DEVICE_SAMPLING: return "DEVICE_SAMPLING";
            case DEVICE_STOPPING: return "DEVICE_STOPPING";
            case DEVICE_ERROR: return "DEVICE_ERROR";
            case DEVICE_MAINTENANCE: return "DEVICE_MAINTENANCE";
            default: return "UNKNOWN";
        }
    }
    
    const char* samplingModeToString(SamplingMode mode)
    {
        switch (mode) {
            case SAMPLING_TIMED: return "SAMPLING_TIMED";
            case SAMPLING_VOLUME: return "SAMPLING_VOLUME";
            default: return "UNKNOWN";
        }
    }
    
    int calculateSamplingTime(int volume, int flowRate)
    {
        if (flowRate <= 0) return 0;
        return (volume * 60) / flowRate; // Convert L/min to seconds
    }
    
    bool validateFlowRate(int rate)
    {
        return rate >= 0 && rate <= 50; // 0-50 L/min range
    }
    
    bool validateSamplingVolume(int volume)
    {
        return volume > 0 && volume <= 1000; // 1-1000 L range
    }
}